package com.lbj.mvvm.update

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.lbj.mvvm.update.net.INetCallback
import com.lbj.mvvm.update.net.INetDownloadCallback
import com.lbj.mvvm.update.net.INetManage
import okhttp3.*
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.concurrent.TimeUnit

class OkHttpNetManager : INetManage {

    companion object {
        private val mOkHttpClient: OkHttpClient = OkHttpClient.Builder()
            .connectTimeout(15, TimeUnit.SECONDS)
            .build()

        // 回调到主线程，故需要使用主线程的Looper
        private val mHandler: Handler = Handler(Looper.getMainLooper())
    }

    override fun get(url: String, callback: INetCallback, tag: Any) {

        val builder: Request.Builder = Request.Builder()
        val request: Request = builder.get().url(url).tag(tag).build()
        val call: Call = mOkHttpClient.newCall(request)
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                mHandler.post {
                    callback.failure(e)
                }
            }

            override fun onResponse(call: Call, response: Response) {
                try {
                    val jsonStr = response.body()?.string() ?: ""
                    // 回调到主线程
                    mHandler.post {
                        callback.success(jsonStr)
                    }
                } catch (e: Throwable) {
                    Log.e("OkHttpNetManager", e.toString())
                    callback.failure(e)
                }
            }
        })
    }

    override fun download(url: String, apkFile: File, callback: INetDownloadCallback, tag: Any) {
        // 判断apkFile是否存在，如果不存在则先创建
        if (!apkFile.exists()) {
            apkFile.parentFile.mkdirs()
        }

        // 请求下载链接
        val request = Request.Builder().get().url(url).tag(tag).build()
        mOkHttpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                mHandler.post { callback.failure(e) }
            }

            override fun onResponse(call: Call, response: Response) {
                var inStream: InputStream? = null
                var outStream: FileOutputStream? = null
                try {
                    // 获取输入流
                    inStream = response.body()?.byteStream()
                    val totalLen = response.body()?.contentLength() ?: 0

                    if (inStream == null) {
                        callback.failure(Exception("没有数据"))
                    } else {
                        // 获取输出流
                        outStream = FileOutputStream(apkFile)


                        val buffer = ByteArray(8 * 1024)
                        var bufferLen: Int
                        var currentLen = 0L
                        // 注意这里的写法与Java中不同，java中使用while循环，这里使用do...while循环
                        // while语法错误：Assigments are not expressions, and only expressions are allowed in this context
                        // assigments不是表达式，在此上下文中只允许表达式
                        // 因为Kotlin不提倡将赋值运算符当做表达式，所以会禁止此举动
                        do {
                            bufferLen = inStream.read(buffer)
                            if (bufferLen != -1) {
                                outStream.write(buffer, 0, bufferLen)
                                outStream.flush()
                                currentLen += bufferLen

                                if (call.isCanceled) break

                                mHandler.post {
                                    callback.progress((currentLen * 1.0f / totalLen * 100).toInt())
                                }
                            } else {
                                break
                            }
                        } while (true)

                        try {
                            // 设置文件可执行，可读写，非自身进程持有
                            apkFile.setExecutable(true, false)
//                            apkFile.setReadable(true, false)
//                            apkFile.setWritable(true, false)
                        } catch (e: Throwable) {
                            e.printStackTrace()
                        }

                        mHandler.post { callback.success(apkFile) }
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                    mHandler.post { callback.failure(e) }
                } finally {
                    inStream?.close()
                    outStream?.close()
                }
            }
        })
    }

    override fun cancel(tag: Any) {
        // OKHttp 有2种队列，一种是正在运行的，一种是等待中的，我们需要取消所有和下载相关的Call
        val runningCalls = mOkHttpClient.dispatcher().runningCalls()
        runningCalls.map { if (tag == it.request().tag()) it.cancel() }
        val queuedCalls = mOkHttpClient.dispatcher().queuedCalls()
        queuedCalls.map { if (tag == it.request().tag()) it.cancel() }
    }
}